// 版权所有2009 Go作者。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package sync

import (
	"internal/race"
	"sync/atomic"
	"unsafe"
)

// 运行时/rwmutex.go中有此文件的修改副本。
// 如果您在此处进行任何更改，请查看是否应在此处进行更改。

// RWMutex是读写器互斥锁。
// 锁可以由任意数量的读卡器或单个写入器持有。
// RWMutex的零值是未锁定的互斥体。
// 
// 首次使用后不得复制RWMutex。
// 
// 如果一个goroutine拥有一个用于读取的RWMutex，而另一个goroutine可能会
// 调用锁，则在释放初始读取锁之前，任何goroutine都不应期望能够获取读取锁
// 。特别是，这禁止
// 递归读取锁定。这是为了确保锁最终变为
// 可用；被阻止的锁调用会使新读卡器无法获取
// 锁。
type RWMutex struct {
	w           Mutex  // 如果有待处理的写入程序
	writerSem   uint32 // 写入程序等待完成的信号
	readerSem   uint32 // 读取程序等待完成的信号
	readerCount int32  // 待处理的读取程序
	readerWait  int32  // 离开的读取程序
}

const rwmutexMaxReaders = 1 << 30

// 发生在关系之前通过：
// /-Unlock->Lock:readerSem 
// /-Unlock->RLock:readerSem 
// /-RUnlock->Lock:writerSem 
// 
// 以下方法暂时禁用对比赛同步
// 事件的处理，以提供更精确的型号以上的比赛
// 探测器。
// 
// 例如，RLock中的atomic.AddInt32不应提供
// 获取发布语义，这将错误地同步竞速
// 读卡器，从而可能丢失竞速。

// RLock锁定rw进行读取。
// 
// 不应用于递归读取锁定；被阻止的锁
// 调用会将新读卡器排除在获取锁之外。请参阅关于RWMutex类型的
// 文档。
func (rw *RWMutex) RLock() {
	if race.Enabled {
		_ = rw.w.state
		race.Disable()
	}
	if atomic.AddInt32(&rw.readerCount, 1) < 0 {
		// 写入程序正在等待，请等待。
		runtime_SemacquireMutex(&rw.readerSem, false, 0)
	}
	if race.Enabled {
		race.Enable()
		race.Acquire(unsafe.Pointer(&rw.readerSem))
	}
}

// RUnlock撤消单个RLock调用；
// 不影响其他同步读卡器。
// 如果rw在进入RUnlock时读取
// 时未被锁定，则为运行时错误。
func (rw *RWMutex) RUnlock() {
	if race.Enabled {
		_ = rw.w.state
		race.ReleaseMerge(unsafe.Pointer(&rw.writerSem))
		race.Disable()
	}
	if r := atomic.AddInt32(&rw.readerCount, -1); r < 0 {
		// 概述了允许内联快速路径的慢速路径
		rw.rUnlockSlow(r)
	}
	if race.Enabled {
		race.Enable()
	}
}

func (rw *RWMutex) rUnlockSlow(r int32) {
	if r+1 == 0 || r+1 == -rwmutexMaxReaders {
		race.Enable()
		throw("sync: RUnlock of unlocked RWMutex")
	}
	// 写入程序挂起。
	if atomic.AddInt32(&rw.readerWait, -1) == 0 {
		// 最后一个读卡器解除对写入器的阻止。
		runtime_Semrelease(&rw.writerSem, false, 1)
	}
}

// 为写入锁定rw。
// 如果锁已经被锁定用于读写，
// 锁将被阻塞，直到锁可用为止。
func (rw *RWMutex) Lock() {
	if race.Enabled {
		_ = rw.w.state
		race.Disable()
	}
	// 首先，解决与其他作家的竞争。
	rw.w.Lock()
	// 向读者宣布，有一位作家正在等待编写。
	r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders
	// 等待活动读卡器。
	if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 {
		runtime_SemacquireMutex(&rw.writerSem, false, 0)
	}
	if race.Enabled {
		race.Enable()
		race.Acquire(unsafe.Pointer(&rw.readerSem))
		race.Acquire(unsafe.Pointer(&rw.writerSem))
	}
}

// 解锁可解锁rw进行写入。如果rw为
// 未锁定以写入要解锁的条目，则为运行时错误。
// 
// 与互斥体一样，锁定的RWMutex与特定的
// GOROUTE不关联。一个goroutine可能会锁定一个RWMutex，然后
// 安排另一个goroutine运行锁定（解锁）它。
func (rw *RWMutex) Unlock() {
	if race.Enabled {
		_ = rw.w.state
		race.Release(unsafe.Pointer(&rw.readerSem))
		race.Disable()
	}

	// 向读者宣布没有活动的编写器。
	r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders)
	if r >= rwmutexMaxReaders {
		race.Enable()
		throw("sync: Unlock of unlocked RWMutex")
	}
	// 取消阻止被阻止的读卡器（如果有）。
	for i := 0; i < int(r); i++ {
		runtime_Semrelease(&rw.readerSem, false, 0)
	}
	// 允许其他写入程序继续。
	rw.w.Unlock()
	if race.Enabled {
		race.Enable()
	}
}

// RLocker通过调用rw.RLock和rw.RUnlock返回实现锁定和解锁方法的锁定器接口。
func (rw *RWMutex) RLocker() Locker {
	return (*rlocker)(rw)
}

type rlocker RWMutex

func (r *rlocker) Lock()   { (*RWMutex)(r).RLock() }
func (r *rlocker) Unlock() { (*RWMutex)(r).RUnlock() }
